import 'dart:ffi';
import 'dart:io';

import 'package:path/path.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart';

///数据库管理工具
///
///[BaseDBProvider]类，这个类定义创建数据库表的基础方法；
///
///这个类是一个抽象类，把具体创建数据库表的sql暴露出去，让子类去具体实现；
///由它直接和DBManager打交道，业务层继承这个接口即可。
abstract class BaseDBProvider {
  bool isTableExits = false;

  ///有子类实现，返回创建表的具体sql
  String tableCreateSql();

  ///有子类实现，返回要创建的表名
  String tableName();

  ///返回表主键字段的基本sql定义，子类把其他字段的sql定义拼接到这个函数的返回值后面即可；
  String tabBaseString(String name, String columnId) {
    return '''create table $name (
    $columnId integer not null primary key autoincrement,
    ''';
  }

  Future<void> prepare(name, String createSql) async {
    isTableExits = await _DBManager.isTableExt(name);
    if (!isTableExits) {
      Database db = await _DBManager._getCurrentDatabase();
      return await db.execute(createSql);
    }
  }

  Future<Database> getDataBase() async {
    if (!isTableExits) {
      await prepare(tableName(), tableCreateSql());
    }
    return await _DBManager._getCurrentDatabase();
  }

  Future<void> close() async => await _DBManager.closeDatabase();

  static init(String? dbName, String databasePath,
          {Function(String path)? copyDB, String? dllPath}) async =>
      await _DBManager.init(dbName, databasePath,
          dllPath: dllPath, copyDB: copyDB);
}

///[_DBManger]类，将数据库的创建，关闭等基础操作同一封装在一个类中统一管理
///
/// 目录定义
/// 1. user 为用户数据,其下按用户账户进行区分 0表示应用级数据目录
/// 2. temp 为缓存目录,就不再区分了,全部公用
/// 3. config 为配置目录
/// 4. platform 为平台相关相关插件,包括服务器server等
/// 5. plugins 为应用插件
/// 6. 全局json用于存储各插件的应用信息，如位置，大小等,数据库用于存储大量插件数据，局部json用于存储少量的插件数据
///
class _DBManager {
  ///数据库版本
  static const int _dbVersion = 1;

  ///内置数据库名称
  static const String _dbName = 'data.db';

  ///数据库实例
  static late Database _database;

  ///数据库名
  ///数据库路径
  ///数据库dllPath
  static init(String? dbName, String databasePath,
      {Function(String path)? copyDB, String? dllPath}) async {
    _setupDatabase(dllPath);
    sqfliteFfiInit();

    if (!Directory(databasePath).existsSync()) {
      Directory(databasePath).createSync(recursive: true);
    }
    //await databaseFactoryFfi.getDatabasesPath();
    final path = join(databasePath, dbName ?? _dbName);

    /// 检查内置数据库，不存在则执行拷贝
    /// 存在则比较是否需要升级
    print('=====$path======数据库检测====');
    if (dbName == null && copyDB != null && !File(path).existsSync()) {
      copyDB.call(path);
    }

    ///打开数据库,如果没有数据库则根据版本，名称，路劲在本地创建数据库并打开数据库
    ///指定[version]时，据库不存在，则调用 [onCreate]
    ///[onUpgrade] [onCreate] 未指定 数据库已经存在并且[版本]高于上一个数据库版本
    _database = await databaseFactoryFfi.openDatabase(path,
        options: OpenDatabaseOptions(
            singleInstance: dbName == null ? false : true,
            version: _dbVersion,
            onCreate: (db, version) {
              //可以在这里创建表
            },
            onConfigure: (db) {},
            onOpen: (db) {},
            onUpgrade: (db, oldVersion, newVersion) {
              ///是否备份原表
              //_doCopyAssetsDb(path);
            }));
  }

  ///判断某个表是否存在
  static isTableExt(String tableName) async {
    String sql =
        "select * from Sqlite_master where type = 'table' and name = '$tableName'";
    var res = await _getCurrentDatabase().rawQuery(sql);
    return res.isNotEmpty;
  }

  ///当前数据库实例
  static _getCurrentDatabase() => _database;

  static closeDatabase() async => await _database.close();
}

_setupDatabase(String? path) {
  path ??= 'sqlite3';
  try {
    DynamicLibrary.open('$path.dll');
  } catch (e) {
    print('Failed to load sqlite3.dll at $path');
    rethrow;
  }
}
